﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace h2100
{
    public class hUnit : hVisibleGameEntity
    {
        /// <summary>
        /// Chỉ ra frame bắt đầu và kết thúc của hành động 
        /// </summary>
        public struct FrameRange
        {
            public int Start;
            public int End;

            public FrameRange(int s, int e)
            {
                Start = s;
                End = e;
            }

            public static bool operator ==(FrameRange a, FrameRange b)
            {
                if (a.Start == b.Start && a.End == b.End)
                    return true;
                return false;
            }

            public static bool operator !=(FrameRange a, FrameRange b)
            {
                if (a.Start != b.Start || a.End != b.End)
                    return true;
                return false;
            }
        }

        #region Properties
        private int[] _actions = new int[9];
        public int[] Actions
        {
            get { return _actions; }
            set { _actions = value; }
        }
        private bool _isSelected = false;
        private float _nextPostX;
        private float _nextPostY;
        private int _id;
        private string _name;
        private int _cost;
        private string _controller;
        private int _power;
        private int _energy;
        private Texture2D _texture;
        private int _nframerow;
        private int _nframecolumn;
        private Texture2D _cursor_select;
        private Texture2D _cursor_select_red;
        private int _currentFrame = 0;
        private FrameRange _currentFrameRange;
        private hGlobal.UnitState _state = hGlobal.UnitState.Appear;
        private bool _isDead=false;
        private bool _acceptMousePress = true;

        private List<hActionButton> _lstAction;
        public List<hActionButton> ActionList
        {
            get { return _lstAction; }
            set { _lstAction = value; }
        }

        private Boolean _clicked = false;
        public Boolean Clicked
        {
            get { return _clicked; }
            set { _clicked = value; }
        }

        public bool IsDead
        {
            get { return _isDead; }
            set { _isDead = value; }
        }

        private FrameRange _appear;
        public FrameRange FRAppear
        {
            get { return _appear; }
            set { _appear = value; }
        }

        private FrameRange _stand;
        public FrameRange FRStand
        {
            get { return _stand; }
            set { _stand = value; }
        }

        private FrameRange _moveup;
        public FrameRange FRMoveUp
        {
            get { return _moveup; }
            set { _moveup = value; }
        }

        private FrameRange _movedown;
        public FrameRange FRMoveDown
        {
            get { return _movedown; }
            set { _movedown = value; }
        }

        private FrameRange _moveleft;
        public FrameRange FRMoveLeft
        {
            get { return _moveleft; }
            set { _moveleft = value; }
        }

        private FrameRange _moveright;
        public FrameRange FRMoveRight
        {
            get { return _moveright; }
            set { _moveright = value; }
        }

        private FrameRange _attackup;
        public FrameRange FRAttackUp
        {
            get { return _attackup; }
            set { _attackup = value; }
        }

        private FrameRange _attackdown;
        public FrameRange FRAttackDown
        {
            get { return _attackdown; }
            set { _attackdown = value; }
        }

        private FrameRange _attackleft;
        public FrameRange FRAttackLeft
        {
            get { return _attackleft; }
            set { _attackleft = value; }
        }

        private FrameRange _attackright;
        public FrameRange FRAttackRight
        {
            get { return _attackright; }
            set { _attackright = value; }
        }

        private FrameRange _die;
        public FrameRange FRDie
        {
            get { return _die; }
            set { _die = value; }
        }

        public int NFrameRow
        {
            get { return _nframerow; }
            set { _nframerow = value; }
        }

        public int NFrameColumn
        {
            get { return _nframecolumn; }
            set { _nframecolumn = value; }
        }

        public Texture2D Texture
        {
            get { return _texture; }
            set { _texture = value; }
        }

        public int Energy
        {
            get { return _energy; }
            set { _energy = value; }
        }

        public int Power
        {
            get { return _power; }
            set { _power = value; }
        }

        public string Controller
        {
            get { return _controller; }
            set { _controller = value; }
        }

        public int Cost
        {
            get { return _cost; }
            set { _cost = value; }
        }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public bool Selected
        {
            get { return _isSelected; }
            set { _isSelected = value; }
        }

        public float NextPostX
        {
            get { return _nextPostX; }
            set { _nextPostX = value; }
        }

        public float NextPostY
        {
            get { return _nextPostY; }
            set { _nextPostY = value; }
        }

        #endregion

        public hVisibleGameEntity clone(hParams args)
        {
            hVisibleGameEntity newObject = new hUnit();
            newObject._nsprite = this._nsprite;
            newObject._sprite = new hSprite[this._nsprite];
            for (int i = 0; i < this._nsprite; i++)
            {
                newObject._sprite[i] = new hSprite(this._sprite[i].Texture);
            }

            newObject.X = this.X;
            newObject.Y = this.Y;
            newObject.Width = this.Width;
            newObject.Height = this.Height;
            ((hUnit)newObject).nDelay = this.nDelay;
            ((hUnit)newObject).Id = this.Id;
            ((hUnit)newObject).Name = this.Name;
            ((hUnit)newObject).Cost = this.Cost;
            ((hUnit)newObject).Controller = this.Controller;
            ((hUnit)newObject).Power = this.Power;
            ((hUnit)newObject).Energy = this.Energy;
            ((hUnit)newObject).Texture = this.Texture;
            ((hUnit)newObject).NFrameRow = this.NFrameRow;
            ((hUnit)newObject).NFrameColumn = this.NFrameColumn;
            ((hUnit)newObject).FRAppear = this.FRAppear;
            ((hUnit)newObject).FRStand = this.FRStand;
            ((hUnit)newObject).FRMoveUp = this.FRMoveUp;
            ((hUnit)newObject).FRMoveDown = this.FRMoveDown;
            ((hUnit)newObject).FRMoveLeft = this.FRMoveLeft;
            ((hUnit)newObject).FRMoveRight = this.FRMoveRight;
            ((hUnit)newObject).FRAttackUp = this.FRAttackUp;
            ((hUnit)newObject).FRAttackDown = this.FRAttackDown;
            ((hUnit)newObject).FRAttackLeft = this.FRAttackLeft;
            ((hUnit)newObject).FRAttackRight = this.FRAttackRight;
            ((hUnit)newObject).FRDie = this.FRDie;
            ((hUnit)newObject)._cursor_select = args.CommonTexture.CursorSelectUnit;
            ((hUnit)newObject)._cursor_select_red = args.CommonTexture.CursorSelectUnitRed;
            ((hUnit)newObject)._currentFrameRange = new FrameRange(this.FRAppear.Start, this.FRAppear.End);
            if (this._actions != null)
            {
                ((hUnit)newObject)._lstAction = new List<hActionButton>();
                for (int i = 0; i < this._actions.Count(); i++)
                {
                    ((hUnit)newObject)._lstAction.Add(args.ActionManager.createObject(this._actions[i]));
                }
            }
            return newObject;
        }
        private bool _isMoving = false;
        private float _nextX;
        private float _nextY;
        public void move(float _x, float _y)
        {
            _isMoving = true;
            _nextX = _x;
            _nextY = _y;
            if(_nextX >= X)
            {
                _state = hGlobal.UnitState.MoveRight;
            }
            if (_nextX <= X)
            {
                _state = hGlobal.UnitState.MoveLeft;
            }
        }

        public void attack(float _x, float _y)
        {

            if (_x >= X)
            {
                _state = hGlobal.UnitState.AttackRight;
            }
            if (_x <= X)
            {
                _state = hGlobal.UnitState.AttackLeft;
            }
        }

        public void endAttack()
        {
            if (_state == hGlobal.UnitState.AttackRight)
            {
                _state = hGlobal.UnitState.MoveRight;
            }
            if (_state == hGlobal.UnitState.AttackLeft)
            {
                _state = hGlobal.UnitState.MoveLeft;
            }
        }

        public int nDelay = 5;
        protected int iDelay = 0;

        public override void update(hParams args, GameTime gameTime)
        {
            if (Power <= 0)
            {
                IsDead = true;
                return;
            }
            if (_isMoving)
            {
                if (X < _nextX)
                {
                    X += 10;
                    if (X > _nextX)
                        X = _nextX;
                }

                if (X > _nextX)
                {
                    X -= 10;
                    if (X < _nextX)
                        X = _nextX;
                }

                if (Y < _nextY)
                {
                    Y += 10;
                    if (Y > _nextY)
                        Y = _nextY;
                }

                if (Y > _nextY)
                {
                    Y -= 10;
                    if (Y < _nextY)
                        Y = _nextY;
                }
                if (X == _nextX && Y == _nextY)
                {
                    X -= Width / 2;
                    Y -= Height / 2;
                    _isMoving = false;
                }
            }

            X += args.Grid.dX;
            Y += args.Grid.dY;

            if (iDelay == 0)
            {
                switch (_state)
                {
                    case hGlobal.UnitState.Appear:
                        if (_currentFrameRange != FRAppear)
                        {
                            _currentFrameRange = FRAppear;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        if (_currentFrame == _currentFrameRange.End)
                        {
                            _state = hGlobal.UnitState.Stand;
                        }
                        break;
                    case hGlobal.UnitState.AttackDown:
                        if (_currentFrameRange != FRAttackDown)
                        {
                            _currentFrameRange = FRAttackDown;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.AttackLeft:
                        if (_currentFrameRange != FRAttackLeft)
                        {
                            _currentFrameRange = FRAttackLeft;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.AttackRight:
                        if (_currentFrameRange != FRAttackRight)
                        {
                            _currentFrameRange = FRAttackRight;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.AttackUp:
                        if (_currentFrameRange != FRAttackUp)
                        {
                            _currentFrameRange = FRAttackUp;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.Die:
                        if (_currentFrameRange != FRDie)
                        {
                            _currentFrameRange = FRDie;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.MoveDown:
                        if (_currentFrameRange != FRMoveDown)
                        {
                            _currentFrameRange = FRMoveDown;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.MoveLeft:
                        if (_currentFrameRange != FRMoveLeft)
                        {
                            _currentFrameRange = FRMoveLeft;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.MoveRight:
                        if (_currentFrameRange != FRMoveRight)
                        {
                            _currentFrameRange = FRMoveRight;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.MoveUp:
                        if (_currentFrameRange != FRMoveUp)
                        {
                            _currentFrameRange = FRMoveUp;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                    case hGlobal.UnitState.Stand:
                        if (_currentFrameRange != FRStand)
                        {
                            _currentFrameRange = FRStand;
                            _currentFrame = _currentFrameRange.Start - 1;
                        }
                        break;
                }
                _currentFrame = _currentFrameRange.Start + (_currentFrame + 1) % (_currentFrameRange.End + 1 - _currentFrameRange.Start);
            }
            iDelay = (iDelay + 1) % nDelay;

            MouseState mouse = Mouse.GetState();   
            // không xử lý chuột nếu chuột trên control panel
            // hay đang trong pha chọn vị trí
            if (args.IsMouseOverControlPanel || args.ControlPhase==hGlobal.ControlPhase.Selecting)
            {
                return;
            }

            if (mouse.LeftButton == ButtonState.Pressed && _acceptMousePress && args.ControlPhase!= hGlobal.ControlPhase.Selecting)
            {
                _acceptMousePress = false;

                if (mouse.X > X && mouse.X < X + Width
                    && mouse.Y > Y && mouse.Y < Y + Height)
                {
                    Clicked = true;
                    if (Controller.Equals("player"))
                    {
                        args.ActionManager.setCurrentActionButtons(ActionList);
                        args.ActionManager.ActionCaller = this;
                    }
                    else
                    {
                        args.ActionManager.setCurrentActionButtons(null);
                    }
                }
                else
                {
                    Clicked = false;
                }
            }

            if (mouse.LeftButton == ButtonState.Released)
            {
                _acceptMousePress = true;
            }
        }

        public new void draw(GameTime gtime, SpriteBatch spriteBatch)
        {
            if (Selected)
            {
                if (this.Controller.Equals("player"))
                {
                    spriteBatch.Draw(_cursor_select, new Vector2(X, Y), Color.White);
                }
                else
                {
                    spriteBatch.Draw(_cursor_select_red, new Vector2(X, Y), Color.White);
                }
            }

            for (int i = 0; i < _nsprite; i++)
            {
                if (!IsDead)
                {
                    _sprite[i].draw(gtime, spriteBatch, new Rectangle((_currentFrame % NFrameColumn) * (int)Width, (_currentFrame / NFrameColumn) * (int)Height, (int)Width, (int)Height), Color.White, new Vector2(0, 0), SpriteEffects.None); ;
                }
                else
                {
                    _sprite[i].draw(gtime, spriteBatch, new Rectangle((_currentFrame % NFrameColumn) * (int)Width, (_currentFrame / NFrameColumn) * (int)Height, (int)Width, (int)Height), new Color(255,255,255,(byte)100), new Vector2(0, 0), SpriteEffects.None); ;
                }
            }
        }
    }
}
